﻿using Microsoft.Extensions.Logging;
using VIA.Integration.Domain;
using VIA.Integration.Domain.Production;
using VIA.SiMoJi.Domain.Option;
using VT.Framework.Scene2D;

namespace VIA.Project.Domain.Services
{
    public interface IAutoDeleteImage
    {
        void Run();
        void Stop();
        DataDeleteOption DataDeleteOption { get; set; }
        DataStorageOption DataStorageOption { get; set; }
    }

    public class AutoDeleteImage : IAutoDeleteImage
    {
        private ManualResetEvent _isDeletRunning = new ManualResetEvent(true);
        private ManualResetEvent _isDeletRunning2 = new ManualResetEvent(true);
        private ILogger _logger;
        System.Timers.Timer _timer;

        public DataDeleteOption DataDeleteOption { get; set; }
        public DataStorageOption DataStorageOption { get; set; }

        public AutoDeleteImage(IOptionRepository optionRepository, ILogger<AutoDeleteImage> logger)
        {
            _logger = logger;
            DataDeleteOption = optionRepository.Get<InspectorOption>().DataDeleteOption;
            DataStorageOption = optionRepository.Get<DataStorageOption>();
            _timer = new(3);
            _timer.Elapsed += Timer_Elapsed;
        }

        public void Run()
        {
            if (DataDeleteOption.IsAutoDeletImage)
                _timer.Start();
        }

        public void Stop()
        {
            _timer.Stop();
        }

        private void Timer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)
        {
            if (_isDeletRunning.WaitOne(0) && CheckDiskFreeSpace(DataStorageOption.SourceImagePath))
            {
                ClearImageFolderByFreeSapce(DataStorageOption.SourceImagePath);
            }
            if (_isDeletRunning2.WaitOne(0))
                ClearImageFolderByTime(DataStorageOption.ResultImagePath);
        }

        private bool CheckDiskFreeSpace(string folderPath)
        {
            DirectoryInfo directoryInfo = new(folderPath);
            if (!directoryInfo.Exists) return false;
            DriveInfo driveInfo = new DriveInfo(directoryInfo.Root.FullName);
            if (driveInfo == null) return false;
            long freeSpace = driveInfo.AvailableFreeSpace / 1024 / 1024 / 1024;
            return freeSpace < DataDeleteOption.DiskFreeSpace;
        }

        private async void ClearImageFolderByFreeSapce(string folderPath)
        {
            DirectoryInfo directoryInfo = new(folderPath);
            if (!directoryInfo.Exists) return;
            var directoryInfos = directoryInfo.GetDirectories().ToList();
            if (directoryInfos.Count == 0) return;
            directoryInfos.Sort((x1, x2) => x1.CreationTime.CompareTo(x2.CreationTime));
            await Task.Run(() =>
            {
                _isDeletRunning.Reset();
                Thread.CurrentThread.Priority = ThreadPriority.BelowNormal;
                try
                {
                    foreach (var item in directoryInfos[0].GetDirectories())
                    {
                        item.Delete(true);
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, ex.Message);
                }
                finally
                {
                    _isDeletRunning.Set();
                }
            });
        }

        private async void ClearImageFolderByTime(string folderPath)
        {
            DirectoryInfo directoryInfo = new(folderPath);
            if (!directoryInfo.Exists) return;
            var directoryInfos = directoryInfo.GetDirectories().ToList();
            if (directoryInfos.Count == 0) return;
            uint days = DataDeleteOption.MaxImgDataTime;
            if (days <= 0) { days = 180; }
            TimeSpan timeSpan = TimeSpan.FromDays(days);
            directoryInfos = directoryInfos.Where(x =>
            {
                TimeSpan created = TimeSpan.FromSeconds((DateTime.Now - x.CreationTime).TotalSeconds);
                return created >= timeSpan;
            }).ToList();
            if (directoryInfos.Count == 0) return;
            await Task.Run(() =>
            {
                _isDeletRunning2.Set();
                Thread.CurrentThread.Priority = ThreadPriority.BelowNormal;
                try
                {
                    foreach (var item in directoryInfos)
                    {
                        foreach (var item2 in item.GetDirectories())
                        {
                            item2.Delete(true);
                        }
                        item.Delete(true);
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, ex.Message);
                }
                finally
                {
                    _isDeletRunning2.Set();
                }
            });
        }
    }
}
